package com.mall.controller;

import com.alibaba.fastjson.JSON;
import com.mall.entity.LoginUser;
import com.mall.entity.SocketUserInfo;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
//客服聊天服务端
//参数role判断用户角色2是客服，1是用户
@ServerEndpoint(value = "/websocket/{role}")
@Component
public class SocketController {

    //用本地线程保存session
    private static ThreadLocal<Session> sessions = new ThreadLocal<Session>();
    //保存所有连接上的用户的session
    private static Map<String, SocketUserInfo> userSessionMap = new ConcurrentHashMap<>();
    //保存在线客服的session
    private static Map<String, SocketUserInfo> serverSessionMap = new ConcurrentHashMap<>();

    @OnOpen//建立链接
    public void onOpen(Session session,EndpointConfig config,@PathParam(value = "role")Integer role){
        //创建建立链接的返回结果
        HashMap<String, String> resultMap = new HashMap<>();
        //默认是失败
        resultMap.put("state","error");
        //保证各个线程里的变量时独立的
        sessions.set(session);
        //判断用户的身份
        //客服上线
        if (role.equals(2)){
            //新建一个客服信息
            SocketUserInfo serverInfo = new SocketUserInfo();
            serverInfo.setUserRole("客服");
            serverInfo.setSession(session);
            serverInfo.setSessionId(session.getId());
            //告诉客服链接成功！
            resultMap.put("state","success");
            //去查询是否有排队等待客服的用户
            if (findLineUser()!=null){
                //获取到那个排队的用户对象
                SocketUserInfo userInfo = userSessionMap.get(findLineUser());
                //给用户绑定好对应的客服
                userInfo.setTargetSessionId(session.getId());
                //覆盖掉之前的未绑定的用户对象
                userSessionMap.put(userInfo.getSessionId(),userInfo);
                //当前链接的客服信息也绑定好对应的用户
                serverInfo.setTargetSessionId(userInfo.getSessionId());
                System.out.println("客服"+serverInfo.getSessionId()+"正在为用户"+userInfo.getSessionId()+"服务");

                //给当前用户和客服显示绑定信息
                HashMap<String, String> result = new HashMap<>();
                //先给当前客服发
                result.put("msg","正在为用户"+userInfo.getSessionId()+"服务");
                send(session,JSON.toJSONString(result));
                //给目标用户发
                result.put("msg","客服"+serverInfo.getSessionId()+"/"+serverInfo.getUsername()+"正在为您服务");
                send(userInfo.getSession(),JSON.toJSONString(result));
            }
            serverSessionMap.put(serverInfo.getSessionId(),serverInfo);
            System.out.println("客服"+serverInfo.getSessionId()+"连接上服务器，当前在线客服共计："+serverSessionMap.size());
        }
        if (role.equals(1)) {

            //创建一个在线用户信息
            SocketUserInfo userInfo = new SocketUserInfo();
            userInfo.setSessionId(session.getId());
            userInfo.setSession(session);
            userInfo.setUserRole("用户");

            //告诉用户连接成功
            resultMap.put("state", "success");

            //去查询是否有在线的客服
            //有空闲客服就将用户和客服绑定
            if (findFreeServer() != null){
                SocketUserInfo serverInfo = serverSessionMap.get(findFreeServer());
                //将用户绑定到客服
                serverInfo.setTargetSessionId(userInfo.getSessionId());
                //覆盖掉之前的客服信息，更新为已绑定的客服信息
                serverSessionMap.put(serverInfo.getSessionId(), serverInfo);
                //将客服绑定到用户
                userInfo.setTargetSessionId(serverInfo.getSessionId());
                System.out.println("客户"+ serverInfo.getSessionId() + "正在为" + userInfo.getSessionId()+"服务");

                Map<String, String> result = new HashMap<>();
                //客服显示用户信息
                result.put("msg", "正在为用户"+userInfo.getSessionId()+"服务！");
                send(serverInfo.getSession(), JSON.toJSONString(result));
                //用户显示客服信息
                result.put("msg", "客服"+serverInfo.getSessionId()+"正在为您服务！");
                send(userInfo.getSession(), JSON.toJSONString(result));
            } else {
                //告诉用户系统繁忙
                resultMap.put("msg", "系统繁忙！");
            }
            //将在线用户信息保存到map中
            userSessionMap.put(session.getId(), userInfo);
            System.out.println("用户编号：" + userInfo.getSessionId() + "连接上服务器，当前在线用户共计：" + userSessionMap.size());
        }
        //返回连接信息
        String jsonResult = JSON.toJSONString(resultMap);
        send(session,jsonResult);
        System.out.println(jsonResult);
    }
    //关闭连接
    @OnClose
    public void onClose(Session session){
        //查看是什么用户连接关闭了
        SocketUserInfo serverInfo = serverSessionMap.get(session.getId());
        //客服下线
        if (serverInfo!=null){
            //那就是客服下线了
            //将客服从集合中删除掉
            serverSessionMap.remove(session.getId());
            //查看是否有客服正在服务的用户对象
            if (serverInfo.getTargetSessionId()!=null){
                //给用户说系统错误
                HashMap<String, String> result = new HashMap<>();
                result.put("msg","客服"+serverInfo.getSessionId()+"掉线，请等待新客服");
                //清除掉用户的客服对象
                SocketUserInfo socketUserInfo = userSessionMap.get(serverInfo.getTargetSessionId());
                socketUserInfo.setTargetSessionId(null);
                userSessionMap.put(serverInfo.getTargetSessionId(),socketUserInfo);

                send(userSessionMap.get(serverInfo.getTargetSessionId()).getSession(),JSON.toJSONString(result));
            }
            System.out.println("客服"+serverInfo.getSessionId()+"退出了服务器，当前在线客服共计："+serverSessionMap.size());
        }else {
            //serverSessionMap里查不到，那就是用户下线了
            //获取用户对象
            SocketUserInfo userInfo = userSessionMap.remove(session.getId());
            //查看是否有正在服务用户的客服，使其解除绑定关系
            //遍历所有的上线客服
            for (SocketUserInfo info : serverSessionMap.values()) {
                if (info.getTargetSessionId()!=null&&(info.getTargetSessionId()==session.getId())){
                    info.setTargetSessionId(null);//解除绑定
                    System.out.println("客服"+info.getSessionId()+"解除了和用户"+session.getId()+"的绑定关系");
                    HashMap<String, String> resultForExit = new HashMap<>();
                    resultForExit.put("msg","用户"+session.getId()+"已经掉线了");
                    send(info.getSession(),JSON.toJSONString(resultForExit));
                    //解绑后看看有没有在等待客服服务的用户，用这个解绑的客服去绑定
                    String lineUser = findLineUser();
                    if (lineUser!=null){
                        //将用户绑定到客服
                        info.setTargetSessionId(lineUser);
                        serverSessionMap.put(info.getSessionId(),info);
                        //将客服绑定给用户
                        SocketUserInfo socketUserInfo = userSessionMap.get(lineUser);
                        socketUserInfo.setTargetSessionId(info.getSessionId());
                        System.out.println("客服"+info.getSessionId()+"正在为用户"+lineUser+"服务");

                        HashMap<String, String> result = new HashMap<>();
                        //客服显示用户信息
                        result.put("msg", "正在为用户"+lineUser+"服务！");
                        send(serverInfo.getSession(), JSON.toJSONString(result));
                        //用户显示客服信息
                        result.put("msg", "客服"+info.getSessionId()+"正在为您服务！");
                        send(userInfo.getSession(), JSON.toJSONString(result));
                    }else {
                        //覆盖点之前有绑定信息的客服对象
                        serverSessionMap.put(info.getSessionId(),info);
                    }
                }
            }
            System.out.println("用户编号：" + userInfo.getSessionId() + "退出链接，当前在线用户共计：" + userSessionMap.size());
        }
    }

    //用户和客户端进行交互传递信息
    @OnMessage
    public void onMessage(String message,Session session){
        //消息
        HashMap<String, String> result = new HashMap<>();
        //尝试从在线客服列表中获取用户信息
        SocketUserInfo serverInfo = serverSessionMap.get(session.getId());
        //客服消息
        if (serverInfo!=null){
            //说明是客服消息
            System.out.println("客服"+serverInfo+"发送了消息:"+message+"  给用户"+serverInfo.getTargetSessionId());
            result.put("msg","客服"+serverInfo.getSessionId()+":"+message);
            //将信息发送给用户
            //先判断是否绑定了用户
            String targetSessionId = serverInfo.getTargetSessionId();
            if (targetSessionId!=null){
                send(userSessionMap.get(targetSessionId).getSession(),JSON.toJSONString(result));
            }else {
                //如果没有就发给自己
                result.put("msg","大哥，你没有给你服务的客户");
                send(session,JSON.toJSONString(result));
            }
        }else {
            //不是客服消息，那么就是用户消息
            System.out.println("用户"+ session.getId()+"发送了消息:"+message+"  给客服"+userSessionMap.get(session.getId()).getTargetSessionId());
            result.put("msg","用户"+session.getId()+":"+message);
            //将消息发送给客服
            SocketUserInfo userInfo = userSessionMap.get(session.getId());
            String targetSessionId = userInfo.getTargetSessionId();
            //先判断用户是否绑定了对应的服务客户
            if (targetSessionId!=null){
                send(serverSessionMap.get(targetSessionId).getSession(),JSON.toJSONString(result));
            }else {
                //如果没有就发给自己
                result.put("msg","大哥，你没有给你服务的客户");
                send(session,JSON.toJSONString(result));
            }
        }
    }
    @OnError
    public void onError(Session session,Throwable throwable){
        System.out.println("发生异常了");
        throwable.printStackTrace();
    }
    //发送信息
    public synchronized void send(Session session,String msg){
        try {
            session.getBasicRemote().sendText(msg);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //查找排队中的用户
    public synchronized String findLineUser(){
        if (userSessionMap.size()>0){
            //如果当前有用户已经上线
            //遍历所有上线的用户，查找没有客服的
            for (SocketUserInfo userInfo : userSessionMap.values()) {
                if (userInfo.getTargetSessionId()==null){
                    return userInfo.getSessionId();
                }
            }
        }
        return null;
    }
    //查找排队中的用户
    public synchronized String findFreeServer(){
        if (serverSessionMap.size()>0){
            //如果当前有用户已经上线
            //遍历所有上线的用户，查找没有客服的
            for (SocketUserInfo serverInfo : serverSessionMap.values()) {
                if (serverInfo.getTargetSessionId()==null){
                    return serverInfo.getSessionId();
                }
            }
        }
        return null;
    }
}
